// 变量声明提升然后赋值

/*
var a
a=2
console.log(a) 
*/
a=2
var a 
console.log(a) //2


/*
var b
console.log(b) 
b=3
*/

console.log(b) //undefined
var b=3


/*
变量声明提升再赋值，
作用域嵌套，如果在当前作用域中无法找到该变量，
引擎会在外层嵌套的作用域中继续查找，直到找到该变量，
或者到达全局作用域
*/
function foo(a) {
    console.log(a + b)
}
var b = 2
foo(1)

function foo1(a) {
    var b = a
    return a + b
}
var c = foo1(9)
console.log(c)

/*
foo函数作用域内有三个变量，a,b,bar
bar函数作用域内只有一个c
函数作用域内变量只在当前作用域内生效，在外使用未定义。查找不到
*/
function foo(a) {
    var b = a * 2
    function bar(c) {
        console.log(a, b, c)

    }
    bar(b * 3)
}
foo(2)

/*
隐藏内部实现 吧变量和函数包裹在一个func函数作用域中，用func来隐藏他们
好处 ，变量函数私有化  避免冲突
*/
//内容私有化 doSomething函数作用域包含a,func b三个变量，对外只暴露了doSomething函数，a,func b访问不到。
function doSomething(a) {
    function func(a) {
        return a - 1
    }
    var b = a + func(a * 2)
    console.log(b * 3)

}
doSomething(2) //15

// 全局命名空间 通常是一个对象,对象也有作用域.对外暴露的功能是这个全局命名空间的属性。
var $ = {
    num: 1,
    fun: function () {
        console.log('fun')
    },
    fun1: function (a) {
        console.log(this) //$对象。
        console.log('fun1' + a)
    }

}
console.log($.fun1('fun1'))
    /*
    立即执行函数表达式  (function foo(){...})() 第一个括号把函数变为函数表达式，第二个()执行这个函数。
    具名和匿名没有任何区别，但是建议加名字。foo在这里加不加无所谓，并且外部是访问不到foo a变量。
    (function(){...}()) ===(function foo(){...})()功能一样
    */

    // 
    (function () {
        var a = 3
        console.log(a)
    })()
console.log(a)//undeifed

// 函数表达式接受传参数
var a = 2;
(function (global) {
    var a = 3
    console.log(a) //3
    console.log(global.a) //2 全局的a
})(window);